package dao

import (
	"common/biz"
	"common/logs"
	"common/utils"
	"context"
	"core/models/db"
	"core/models/entity"
	"core/repo"
	"encoding/json"
	"fmt"
	"framework/msError"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"gorm.io/gorm"
	"hall/models/request"
	hall "hall/models/response"
	"math"
	"time"
)

type WarehouseDao struct {
	base *BaseDao
	repo *repo.Manager
}

func (d *WarehouseDao) StarGame(user []uint, score int64, roomID string) error {
	typeID := 12
	ctx := context.TODO()
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	mtx, _ := _mdb.Client.StartSession()
	_ = mtx.StartTransaction()
	defer mtx.EndSession(ctx)
	var err error
	for _, uid := range user {
		//1.查询材料是否充足
		material := new(db.WarehouseMaterialHasOneType)
		_db.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, typeID).Preload("Types").First(&material)
		if material.Num < score {
			err = fmt.Errorf("[GameHandler]用户%d StarGame err:材料不足", uid)
			break
		}
		err = tx.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, typeID).Update("num", gorm.Expr("num-?", score)).Error
		if err != nil {
			err = fmt.Errorf("[GameHandler]用户%d StarGame err:sql扣除材料失败,dbErr:%v", uid, err)
			break
		}
		//2.添加材料变更记录
		collection := _mdb.Db.Collection("material_log")
		materialLog := &entity.MaterialLog{
			UID:        uid,
			WID:        material.ID,
			TypeID:     material.TypeID,
			TypeName:   material.Types.Name,
			TypeImg:    material.Types.Img,
			TypeModule: material.Types.Module,
			LinkID:     roomID,
			LinkTable:  "m_game_card_room_log",
			Ago:        material.Num,
			Num:        -score,
			After:      material.Num - score,
			Remarks:    "游戏-卡牌",
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = collection.InsertOne(ctx, materialLog)
		if err != nil {
			err = fmt.Errorf("[GameHandler]用户%d StarGame err:材料变更记录添加失败,res=%v,dbErr:%v", uid, materialLog, err)
			break
		}
		//3.添加游戏记录
		collectionLog := _mdb.Db.Collection("game_card_room_log")
		gameCardRoomLog := &entity.GameCardRoomLog{
			UID:        uid,
			RoomID:     roomID,
			TypeID:     material.TypeID,
			TypeName:   material.Types.Name,
			TypeImg:    material.Types.Img,
			TypeModule: material.Types.Module,
			Num:        score,
			Dates:      utils.TimeOrDateAsYear(0, "", "Y-m-d"),
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = collectionLog.InsertOne(ctx, gameCardRoomLog)
		if err != nil {
			err = fmt.Errorf("[GameHandler]用户%d StarGame err:添加游戏记录失败,res=%v,dbErr:%v", uid, gameCardRoomLog, err)
			break
		}
		//4.添加游戏记录
		gameCardLog := &entity.GameCardLog{
			UID:     uid,
			RoomID:  roomID,
			AddTime: time.Now().Format(time.DateTime),
		}
		_, err = _mdb.Db.Collection("game_card_log").InsertOne(ctx, gameCardLog)
		if err != nil {
			err = fmt.Errorf("[GameHandler]用户%d StarGame err:添加游戏记录失败,res=%v,dbErr:%v", uid, gameCardLog, err)
			break
		}
	}
	if err != nil {
		logs.Error("%v", err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return err
	}
	_ = mtx.CommitTransaction(ctx)
	tx.Commit()
	return nil
}

func (d *WarehouseDao) GetMaterial(ctx context.Context, uid uint, req *request.WarehouseScreen) *[]db.WarehouseMaterialHasOneType {
	data := new([]db.WarehouseMaterialHasOneType)
	whe := map[string]any{
		"uid": uid,
	}
	if req.Type != 0 {
		whe["type_id"] = req.Type
	}

	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseMaterial{}).
		Where(whe).
		Preload("Types", func(db *gorm.DB) *gorm.DB {
			if req.TypeTwo != 0 {
				db = db.Where("types=?", req.TypeTwo)
			}
			return db
		}).
		Preload("Donate").
		Preload("Donate.LinkType").
		Preload("Donate.LinkRole").
		Find(data)
	return data
}
func (d *WarehouseDao) GetCard(ctx context.Context, uid uint, req *request.WarehouseScreen) *[]db.WarehouseCardHasOneType {
	data := new([]db.WarehouseCardHasOneType)
	whe := map[string]any{
		"uid":        uid,
		"is_abandon": false,
		"is_use":     false,
		"is_freeze":  false,
	}
	if req.Type != 0 {
		whe["type_id"] = req.Type
	}
	if req.IsNew {
		whe["is_new"] = req.IsNew
	}
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseCard{}).
		Where(whe).
		Preload("Types", func(db *gorm.DB) *gorm.DB {
			if req.TypeTwo != 0 {
				db = db.Where("types=?", req.TypeTwo)
			}
			return db
		}).
		Preload("TypeCard", func(db *gorm.DB) *gorm.DB {
			if req.IsProduction {
				db = db.Where("level<?", 5)
			}
			return db
		}).
		Order("id desc").
		Find(data)
	return data
}
func (d *WarehouseDao) GetEquip(ctx context.Context, uid uint, req *request.WarehouseScreen) *[]db.WarehouseEquipHasOneType {
	data := new([]db.WarehouseEquipHasOneType)
	whe := map[string]any{
		"uid":        uid,
		"is_abandon": false,
		"is_use":     false,
		"is_freeze":  false,
	}
	if req.Type != 0 {
		whe["type_id"] = req.Type
	}
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseEquip{}).
		Where(whe).
		Preload("Types", func(db *gorm.DB) *gorm.DB {
			if req.TypeTwo != 0 {
				db = db.Where("types=?", req.TypeTwo)
			}
			return db
		}).
		Preload("Conf").
		Find(data)
	return data
}

func (d *WarehouseDao) GetMaterialInfo(ctx context.Context, uid, id uint) *db.WarehouseMaterialHasOneType {
	data := new(db.WarehouseMaterialHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseMaterial{}).
		Where("id=? AND uid=?", id, uid).
		Preload("Types").
		Preload("Donate").
		Preload("Donate.LinkType").
		Preload("Donate.LinkRole").
		First(data)
	return data
}
func (d *WarehouseDao) GetCardInfo(ctx context.Context, uid uint, id uint) *db.WarehouseCardHasOneType {
	data := new(db.WarehouseCardHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseCard{}).
		Where("id=? AND uid=? AND is_abandon=? AND is_freeze=?", id, uid, false, false).
		Preload("Types").
		Preload("TypeCard").
		Preload("TypeCard.ConsumeType").
		Preload("TypeCard.OutputType").
		Find(data)
	return data
}
func (d *WarehouseDao) GetEquipInfo(ctx context.Context, uid uint, id uint) *db.WarehouseEquipHasOneType {
	data := new(db.WarehouseEquipHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseEquip{}).
		Where("id=? AND uid=? AND is_abandon=? AND is_freeze=?", id, uid, false, false).
		Preload("Types").
		Preload("Conf").
		Find(data)
	return data
}

// GetMarketCardInfo 市场读取卡牌信息
func (d *WarehouseDao) GetMarketCardInfo(ctx context.Context, uid uint, id uint) *db.WarehouseCardHasOneType {
	data := new(db.WarehouseCardHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseCard{}).
		Where("id=? AND uid=? ", id, uid).
		Preload("Types").
		Preload("TypeCard").
		Preload("TypeCard.ConsumeType").
		Preload("TypeCard.OutputType").
		Find(data)
	return data
}

func (d *WarehouseDao) GetMaterialInfoByTypeID(ctx context.Context, uid uint, typeID uint) *db.WarehouseMaterialHasOneType {
	var data = new(db.WarehouseMaterialHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(&db.WarehouseMaterial{}).
		Where("uid=? AND type_id=?", uid, typeID).
		Preload("Types").
		Preload("Donate").
		Preload("Donate.LinkType").
		Preload("Donate.LinkRole").
		First(data)
	return data
}

func (d *WarehouseDao) OpenCardPackage(ctx context.Context, data *db.WarehouseMaterialHasOneType) ([]uint, int, any, *msError.Error) {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	var cards, haxCards []uint
	var packageCards []entity.Card
	var donate any
	var typeI = -1
	//1.扣除数量
	err := tx.Model(db.WarehouseMaterial{}).Where("id=?", data.ID).Update("num", gorm.Expr("num-?", 1)).Error
	if err != nil {
		err = fmt.Errorf("[warehouseHandler]用户%d OpenCardPackage err:扣除数量失败,res=%v,dbErr:%v", data.UID, data, err)
		logs.Error("%v", err)
		return cards, 0, donate, biz.SqlError
	}
	//添加材料变动
	collection := d.repo.Mongo.Db.Collection("material_log")
	materialLog := &entity.MaterialLog{
		UID:        data.UID,
		WID:        data.ID,
		TypeID:     data.TypeID,
		TypeName:   data.Types.Name,
		TypeImg:    data.Types.Img,
		TypeModule: data.Types.Module,
		LinkID:     "",
		LinkTable:  "",
		Ago:        data.Num,
		Num:        -1,
		After:      data.Num - 1,
		Remarks:    "仓库-开启卡包",
		AddTime:    time.Now().Format(time.DateTime),
	}
	_, err = collection.InsertOne(ctx, materialLog)
	if err != nil {
		logs.Error("[warehouseHandler]用户%d OpenCardPackage err:材料变更记录添加失败,res=%v,dbErr:%v", data.UID, materialLog, err)
		tx.Rollback()
		return cards, 0, donate, biz.SqlError
	}
	//2.循环添加卡牌
	for i := 0; i < int(data.Types.Val); i++ {
		rands := utils.Random(1, 1000)
		typeCard := new(db.TypeCard)
		if data.TypeID != 16 {
			_db.Model(typeCard).Where("is_ini=? AND rate<=? AND rate_max>=?", true, rands, rands).First(typeCard)
		} else {
			_db.Model(typeCard).Where("is_ini=? AND integral_rate<=? AND integral_rate_max>=?", true, rands, rands).First(typeCard)
		}
		rate := utils.Random(int(typeCard.Output), int(typeCard.OutputMax))
		card := &db.WarehouseCard{
			UID:         data.UID,
			TypeID:      typeCard.TypeID,
			TypeCardID:  typeCard.ID,
			Num:         typeCard.TotalOutput,
			Rate:        rate,
			IsAbandon:   false,
			IsUse:       false,
			IsNew:       true,
			IsFreeze:    false,
			IsChain:     0,
			Hax:         nil,
			OperationID: "",
			TokenID:     nil,
		}
		err = tx.Model(card).Create(card).Error
		if err != nil {
			err = fmt.Errorf("[warehouseHandler]用户%d OpenCardPackage err:添加卡牌失败,res=%v,dbErr:%v", data.UID, typeCard, err)
			break
		}
		types := new(db.Type)
		_db.Where("id=?", card.TypeID).First(types)
		packageCards = append(packageCards, entity.Card{
			WID:        card.ID,
			TypeID:     card.TypeID,
			TypeName:   types.Name,
			TypeImg:    types.Img,
			TypeModule: types.Module,
		})
		//NFT添加一个tokenID
		widLen := len(fmt.Sprintf("%d", card.ID))
		var widStr string
		if widLen < 8 {
			for i := 0; i < 8-widLen; i++ {
				widStr += "0"
			}
		}
		widStr += fmt.Sprintf("%d", card.ID)
		tokenID := fmt.Sprintf("S%v", widStr)
		card.TokenID = &tokenID
		err = tx.Save(card).Error
		if err != nil {
			err = fmt.Errorf("[warehouseHandler]用户%d OpenCardPackage err:上链失败,res=%v,dbErr:%v", data.UID, typeCard, err)
			break
		}
		haxCards = append(haxCards, card.ID)
	}
	if err != nil {
		logs.Error("%v", err)
		tx.Rollback()
		return cards, 0, donate, biz.SqlError
	}
	cards = haxCards
	//3.有赠送添加赠送物品
	var donateMap map[string]any
	if len(data.Donate) > 0 {
		rands := utils.Random(1, 100)
		var odds int64
		var v db.TypeCardDonateHaxOneTypeOfRole
		for _, v = range data.Donate {
			if rands > odds && rands <= odds+v.Odds {
				break
			}
			odds += v.Odds
		}
		typeI = 0
		if v.Type == 1 { //游戏角色
			gameRole := new(db.GameRole)
			var roleCount int64
			_db.Model(gameRole).Where("uid=? AND role_id=?", data.UID, v.LinkRole.ID).Count(&roleCount)
			if roleCount <= 0 {
				gameRole = &db.GameRole{
					GameID: 1,
					UID:    data.UID,
					RoleID: v.LinkRole.ID,
				}
				err = tx.Model(gameRole).Create(gameRole).Error
				if err != nil {
					err = fmt.Errorf("[warehouseHandler]用户%d OpenCardPackage err:添加游戏角色失败,res=%v,dbErr:%v", data.UID, v.LinkRole, err)
					logs.Error("%v", err)
					tx.Rollback()
					return []uint{}, 0, donate, biz.SqlError
				}
				gameRolePool := new(db.GameRolePool)
				_db.Model(gameRolePool).Where("id=?", gameRole.RoleID).First(gameRolePool)
				donateMap = map[string]any{
					"name":   gameRolePool.Name,
					"img":    gameRolePool.Img,
					"avatar": gameRolePool.Avatar,
					"desc":   gameRolePool.Desc,
				}
				donate = donateMap
			} else {
				for _, val := range data.Donate {
					if val.Type == 2 {
						v = val
						break
					}
				}
			}
		}
		if v.Type == 2 { //材料
			typeI = v.LinkType.Type
			switch v.LinkType.Type {
			case 1: //卡牌
				typeCard := new(db.TypeCard)
				_db.Model(typeCard).Where("type_id=? AND is_ini=?", v.LinkID, true)
				rate := utils.Random(int(typeCard.Output), int(typeCard.OutputMax))
				card := &db.WarehouseCard{
					UID:         data.UID,
					TypeID:      v.LinkID,
					TypeCardID:  typeCard.ID,
					Num:         typeCard.TotalOutput,
					Rate:        rate,
					IsNew:       true,
					IsFreeze:    false,
					IsChain:     0,
					Hax:         nil,
					OperationID: "",
					TokenID:     nil,
				}
				err = tx.Model(card).Create(card).Error
				if err != nil {
					logs.Error("[warehouseHandler]用户%d OpenCardPackage err:添加卡牌失败,res=%v,dbErr:%v", data.UID, v.LinkType, err)
					tx.Rollback()
					return []uint{}, 0, donate, biz.SqlError
				}
				//NFT添加一个tokenID
				widLen := len(fmt.Sprintf("%d", card.ID))
				var widStr string
				if widLen < 8 {
					for i := 0; i < 8-widLen; i++ {
						widStr += "0"
					}
				}
				widStr += fmt.Sprintf("%d", card.ID)
				tokenID := fmt.Sprintf("S%v", widStr)
				card.TokenID = &tokenID
				err = tx.Save(card).Error
				if err != nil {
					logs.Error("[warehouseHandler]用户%d OpenCardPackage err:上链失败,res=%v,dbErr:%v", data.UID, v.LinkType, err)
					tx.Rollback()
					return []uint{}, 0, donate, biz.SqlError
				}
				haxCards = append(haxCards, card.ID)
				types := new(db.Type)
				typeInfo := types
				_db.Model(types).Where("id=?", card.TypeID).First(types)
				_db.Model(typeInfo).Where("id=?", 11).First(typeInfo)
				donateCard := hall.CardData{
					WID:         card.ID,
					TypeID:      card.TypeID,
					TypeName:    types.Name,
					TypeImg:     types.Img,
					TypeModule:  types.Module,
					TypeDesc:    types.Desc,
					TypeType:    types.Type,
					TypeTypes:   types.Types,
					SyOutput:    utils.DecimalIntDiv(card.Num, typeInfo.Val),
					TotalOutput: utils.DecimalIntDiv(typeCard.TotalOutput, typeInfo.Val),
					OutputRate:  utils.DecimalIntDiv(card.Rate, typeInfo.Val),
					Level:       typeCard.Level,
					IsNew:       card.IsNew,
					Token:       card.TokenID,
					Hax:         card.Hax,
				}
				marshal, _ := json.Marshal(donateCard)
				_ = json.Unmarshal(marshal, &donateMap)
				donate = donateCard
				break
			case 2: //材料
				material := new(db.WarehouseMaterial)
				_db.Model(material).Where("uid=? AND type_id=?", data.UID, v.LinkID).First(material)
				err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num+?", v.Num)).Error
				if err != nil {
					logs.Error("[warehouseHandler]用户%d OpenCardPackage err:添加材料失败,res=%v,dbErr:%v", data.UID, v.LinkType, err)
					tx.Rollback()
					return []uint{}, 0, donate, biz.SqlError
				}
				//2.添加材料变更记录
				materialLog = &entity.MaterialLog{
					UID:        data.UID,
					WID:        material.ID,
					TypeID:     material.TypeID,
					TypeName:   v.LinkType.Name,
					TypeImg:    v.LinkType.Img,
					TypeModule: v.LinkType.Module,
					LinkID:     "",
					LinkTable:  "",
					Ago:        material.Num,
					Num:        v.Num,
					After:      material.Num + v.Num,
					Remarks:    "仓库-开卡包-赠送",
					AddTime:    time.Now().Format(time.DateTime),
				}
				_, err = collection.InsertOne(ctx, materialLog)
				if err != nil {
					logs.Error("[warehouseHandler]用户%d OpenCardPackage err:材料变更记录添加失败,res=%v,dbErr:%v", data.UID, materialLog, err)
					tx.Rollback()
					return []uint{}, 0, donate, biz.SqlError
				}
				donateMap = map[string]any{
					"typeID":   v.LinkID,
					"typeName": v.LinkType.Name,
					"typeImg":  v.LinkType.Img,
					"num":      v.Num,
				}
				donate = donateMap
				break
			case 3: //装备
				typeEquip := new(db.TypeEquip)
				_db.Model(&db.TypeEquip{}).Where("type_id=?", v.LinkID).First(typeEquip)
				equip := &db.WarehouseEquip{
					UID:      data.UID,
					TypeID:   typeEquip.TypeID,
					SyNum:    typeEquip.Term,
					IsNew:    true,
					IsFreeze: false,
				}
				err = tx.Model(equip).Create(equip).Error
				if err != nil {
					logs.Error("[warehouseHandler]用户%d OpenCardPackage err:添加装备失败,res=%v,dbErr:%v", data.UID, typeEquip, err)
					tx.Rollback()
					return []uint{}, 0, donate, biz.SqlError
				}
				types := new(db.Type)
				_db.Model(types).Where("id=?", equip.TypeID).First(types)
				donateEquip := hall.EquipData{
					WID:        equip.ID,
					TypeID:     equip.TypeID,
					TypeName:   types.Name,
					TypeImg:    types.Img,
					TypeModule: types.Module,
					TypeDesc:   types.Desc,
					TypeType:   types.Type,
					TypeTypes:  types.Types,
					Num:        equip.SyNum,
					SyNum:      equip.SyNum,
					Increase:   utils.DecimalIntDiv(typeEquip.Increase, 100),
				}
				marshal, _ := json.Marshal(donateEquip)
				_ = json.Unmarshal(marshal, &donateMap)
				donate = donateEquip
				break
			}
		}
	}
	//4.添加打开礼包记录
	cardPackage := entity.CardPackage{
		UID:        data.UID,
		WID:        data.ID,
		TypeID:     data.TypeID,
		TypeName:   data.Types.Name,
		TypeImg:    data.Types.Img,
		TypeModule: data.Types.Module,
		TypeType:   data.Types.Type,
		Cards:      packageCards,
		DonateType: typeI,
		DonateMap:  donateMap,
		AddTime:    time.Now().Format(time.DateTime),
	}
	packageLog := d.repo.Mongo.Db.Collection("card_package_log")
	_, err = packageLog.InsertOne(ctx, cardPackage)
	if err != nil {
		logs.Error("[warehouseHandler]用户%d OpenCardPackage err:添加卡包记录失败,res=%v,dbErr:%v", data.UID, materialLog, err)
		tx.Rollback()
		return cards, 0, donate, biz.SqlError
	}
	// TODO 4.上链
	//for _, v := range haxCards {
	//	go d.base.TimingObtainHax(data.UID, v)
	//}
	tx.Commit()
	return cards, typeI, donate, nil
}

// InitWarehouseInsert 初始化添加材料记录
func (d *WarehouseDao) InitWarehouseInsert(ctx context.Context, uid uint) error {
	types := new([]db.Type)
	d.repo.DB.Client.WithContext(ctx).Model(types).Where("is_default=?", true).Find(types)
	for _, v := range *types {
		material := &db.WarehouseMaterial{
			UID:    uid,
			TypeID: v.ID,
		}
		if err := d.repo.DB.Client.WithContext(ctx).Model(material).Create(material).Error; err != nil {
			return err
		}
	}
	return nil
}

func (d *WarehouseDao) GetCardTypeCount(ctx context.Context, id, uid, typeCardID uint) int64 {
	var count int64
	d.repo.DB.Client.WithContext(ctx).Model(db.WarehouseCard{}).Where("id<>? AND type_card_id=? AND uid=? AND is_abandon=? AND is_use=? AND is_new=? AND is_freeze=?", id, typeCardID, uid, false, false, true, false).Count(&count)
	return count
}

func (d *WarehouseDao) WarehouseCardUpgrade(ctx context.Context, data *db.WarehouseCardHasOneType, nextTypeCard *db.TypeCardHaseOneType) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	mtx, _ := _mdb.Client.StartSession()
	_ = mtx.StartTransaction()
	defer mtx.EndSession(ctx)
	var err error
	//1.扣除材料
	if nextTypeCard.ConsumeTypeID != 0 {
		material := new(db.WarehouseMaterial)
		materialType := new(db.WarehouseMaterialHasOneType)
		_db.Model(material).Where("uid=? AND type_id=?", data.UID, nextTypeCard.ConsumeTypeID).Preload("Types").First(materialType)
		if materialType.Num < nextTypeCard.ConsumeNum {
			logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:材料不足,res=%v", data.UID, materialType)
			return biz.GoodsPayError
		}
		err = tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num-?", nextTypeCard.ConsumeNum)).Error
		if err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:材料扣除失败,res=%v,dbErr:%v", data.UID, nextTypeCard, err)
			return biz.SqlError
		}
		materialLog := &entity.MaterialLog{
			UID:        data.UID,
			WID:        materialType.ID,
			TypeID:     materialType.TypeID,
			TypeName:   materialType.Types.Name,
			TypeImg:    materialType.Types.Img,
			TypeModule: materialType.Types.Module,
			LinkID:     fmt.Sprintf("%d", data.ID),
			LinkTable:  "m_card_upgrade_og",
			Ago:        materialType.Num,
			Num:        -nextTypeCard.ConsumeNum,
			After:      materialType.Num - nextTypeCard.ConsumeNum,
			Remarks:    "仓库-升级卡牌",
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
		if err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:材料变更记录添加失败,res=%v,dbErr:%v", data.UID, materialLog, err)
			tx.Rollback()
			return biz.SqlError
		}
	}
	//2.扣除卡牌
	initTypeCard := new(db.TypeCard)
	_db.Model(initTypeCard).Where("type_id=? AND is_ini=?", data.TypeID, true).First(initTypeCard)
	var cardId []uint
	card := new([]db.WarehouseCard)
	_db.Model(&db.WarehouseCard{}).Where("id<>? AND type_card_id=? AND uid=? AND is_abandon=? AND is_use=? AND is_new=? AND is_freeze=?", data.ID, initTypeCard.ID, data.UID, false, false, true, false).Limit(int(nextTypeCard.UpgradeCardNum)).Find(&card)
	if len(*card) < int(nextTypeCard.UpgradeCardNum) {
		logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:可升级卡牌数量不足,res=%v,dbErr:%v", data.UID, card, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	for _, v := range *card {
		cardId = append(cardId, v.ID)
		err = tx.Model(card).Where("id=?", v.ID).Updates(&map[string]any{
			"is_abandon": true,
			"is_new":     false,
		}).Error
		if err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:卡牌扣除失败,res=%v,dbErr:%v", data.UID, v, err)
			break
		}
	}
	if err != nil {
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//3.修改升级卡的数值
	donation := nextTypeCard.TotalOutput - data.TypeCard.TotalOutput
	var outNum int64 = 100000
	outMin := nextTypeCard.Output / outNum
	outMax := nextTypeCard.OutputMax / outNum
	rate := utils.Random(int(outMin), int(outMax))
	rate *= outNum
	cardUp := map[string]any{
		"num":          gorm.Expr("num+?", donation),
		"rate":         rate,
		"type_card_id": nextTypeCard.ID,
	}
	err = tx.Model(&db.WarehouseCard{}).Where("id=?", data.ID).Updates(cardUp).Error
	if err != nil {
		logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:升级卡牌数值修改失败,res=%v,dbErr:%v", data.UID, cardUp, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//4.添加升级记录
	cardIdByte, _ := json.Marshal(cardId)
	cardUpgradeLog := &entity.CardUpgradeLog{
		UID:         data.UID,
		WID:         data.ID,
		TypeID:      data.TypeID,
		TypeName:    data.Types.Name,
		TypeImg:     data.Types.Img,
		TypeModule:  data.Types.Module,
		ConsumeWID:  string(cardIdByte),
		TotalAgo:    data.Num,
		TotalAfter:  data.Num + donation,
		OutputAgo:   data.Rate,
		OutputAfter: rate,
		AddTime:     time.Now().Format(time.DateTime),
	}
	_, err = _mdb.Db.Collection("card_upgrade_og").InsertOne(ctx, cardUpgradeLog)
	if err != nil {
		logs.Error("[warehouseHandler]用户%d WarehouseCardUpgrade err:升级记录添加失败,res=%v,dbErr:%v", data.UID, cardUpgradeLog, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	tx.Commit()
	_ = mtx.CommitTransaction(ctx)
	return nil
}

func (d *WarehouseDao) WarehouseGoldTransfer(ctx context.Context, req *request.WarehouseGoldTransfer, user *db.UserHasOneRole, otherUser *db.UserHasOneRole, transferFee float64, divideInto *[]db.UserHasOneRole) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	mtx, _ := _mdb.Client.StartSession()
	_ = mtx.StartTransaction()
	defer mtx.EndSession(ctx)
	//1.查询自己的材料信息
	types := new(db.Type)
	_db.Model(types).First(types, req.TypeID)
	if !types.IsTransfer {
		logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:该类型不可转让,res=%v", user.ID, types)
		return biz.RequestDataError
	}
	if req.TypeID == 11 {
		req.Num = utils.DecimalFloatByInt(utils.DecimalFloatMul(utils.DecimalIntByFloat(req.Num), utils.DecimalIntByFloat(types.Val)))
	}
	var err error
	var fee, OtherObtainFee, num, total int64
	var wid, otherWid uint
	num = req.Num
	total = num
	switch req.Type {
	case 1:
		req.Num = 1
		card := new(db.WarehouseCard)
		_db.Model(card).Where("id=? AND uid=? AND is_abandon=? AND is_use=? AND is_freeze=?", req.ID, user.ID, false, false, false).First(card)
		if card == nil || card.ID == 0 {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:卡牌不存在,res=%v", user.ID, types)
			return biz.RequestDataError
		}
		if err = tx.Model(card).Where("id=?", card.ID).Update("uid=?", otherUser.ID).Error; err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:转让失败,res=%v,dbErr:%v", user.ID, card, err)
			return biz.SqlError
		}
		wid = card.ID
		otherWid = card.ID
		break
	case 2:
		if req.TypeID == 11 || req.TypeID == 12 || req.TypeID == 13 {
			if transferFee > 0 {
				fee = utils.DecimalFloatByInt(utils.DecimalFloatMul(utils.DecimalIntByFloat(num), transferFee))
			}
			total += fee
			if otherUser.Role.ChamberMember.LevelID != 0 && fee != 0 {
				otherTransferFee := utils.DecimalIntDiv(otherUser.Role.ChamberMember.Conf.Profit, 100)
				OtherObtainFee = utils.DecimalFloatByInt(utils.DecimalFloatMul(utils.DecimalIntByFloat(req.Num), otherTransferFee))
			}
			//num += OtherObtainFee
		}
		//扣除方
		material := new(db.WarehouseMaterial)
		_db.Model(material).Where("id=? AND uid=?", req.ID, user.ID).First(material)
		if material == nil || material.ID == 0 {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料不存在,res=%v", user.ID, types)
			return biz.NotEnoughGold
		}
		if material.Num < total {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:数量不足,res=%v", user.ID, material)
			return biz.NotEnoughGold
		}
		if err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num-?", total)).Error; err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料扣除失败,res=%v,dbErr:%v", user.ID, material, err)
			return biz.SqlError
		}
		materialLog := &entity.MaterialLog{
			UID:        user.ID,
			WID:        material.ID,
			TypeID:     material.TypeID,
			TypeName:   types.Name,
			TypeImg:    types.Img,
			TypeModule: types.Module,
			LinkID:     fmt.Sprintf("%d", material.ID),
			LinkTable:  "m_transfer_log",
			Ago:        material.Num,
			Num:        -total,
			After:      material.Num - total,
			Remarks:    fmt.Sprintf("仓库-转赠给-#%v", otherUser.InviteCode),
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
		if err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料变更记录添加失败,res=%v,dbErr:%v", user.ID, materialLog, err)
			tx.Rollback()
			return biz.SqlError
		}
		//接收方
		materialType2 := new(db.WarehouseMaterial)
		_db.Model(materialType2).Where("uid=? AND type_id=?", otherUser.ID, material.TypeID).First(materialType2)
		if materialType2 == nil || materialType2.ID == 0 {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料不存在,res=%v", otherUser.ID, materialType2)
			tx.Rollback()
			_ = mtx.AbortTransaction(ctx)
			return biz.RequestDataError
		}
		if err = tx.Model(materialType2).Where("id=?", materialType2.ID).Update("num", gorm.Expr("num+?", num)).Error; err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料增加失败,res=%v,dbErr:%v", otherUser.ID, materialType2, err)
			tx.Rollback()
			_ = mtx.AbortTransaction(ctx)
			return biz.SqlError
		}
		materialLog = &entity.MaterialLog{
			UID:        otherUser.ID,
			WID:        materialType2.ID,
			TypeID:     materialType2.TypeID,
			TypeName:   types.Name,
			TypeImg:    types.Img,
			TypeModule: types.Module,
			LinkID:     fmt.Sprintf("%d", material.ID),
			LinkTable:  "m_transfer_log",
			Ago:        materialType2.Num,
			Num:        num,
			After:      materialType2.Num + num,
			Remarks:    fmt.Sprintf("仓库-#%v-转赠", user.InviteCode),
			AddTime:    time.Now().Format(time.DateTime),
		}
		_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
		if err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料变更记录添加失败,res=%v,dbErr:%v", otherUser.ID, materialLog, err)
			tx.Rollback()
			_ = mtx.AbortTransaction(ctx)
			return biz.SqlError
		}
		wid = material.ID
		otherWid = materialType2.ID
		break
	case 3:
		req.Num = 1
		equip := new(db.WarehouseEquip)
		_db.Model(equip).Where("id=? AND uid=? AND is_abandon=? AND is_use=? AND is_freeze=?", req.ID, user.ID, false, false, false).First(equip)
		if equip == nil || equip.ID == 0 {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:装备不存在,res=%v", user.ID, types)
			return biz.RequestDataError
		}
		if err = tx.Model(equip).Where("id=?", equip.ID).Update("uid=?", otherUser.ID).Error; err != nil {
			logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:转让失败,res=%v,dbErr:%v", user.ID, equip, err)
			return biz.SqlError
		}
		wid = equip.ID
		otherWid = equip.ID
		break
	}
	//添加转出记录
	transferLog := &entity.TransferLog{
		UID:             user.ID,
		Phone:           user.Username,
		InviteCode:      user.InviteCode,
		Other:           otherUser.ID,
		OtherPhone:      otherUser.Username,
		OtherInviteCode: otherUser.InviteCode,
		Type:            1,
		WID:             wid,
		TypeID:          types.ID,
		TypeName:        types.Name,
		TypeImg:         types.Img,
		TypeModule:      types.Module,
		TypeType:        types.Type,
		Num:             req.Num,
		Fee:             utils.DecimalIntByFloat(fee),
		Obtain:          0,
		OtherNum:        0,
		OtherObtainFee:  0,
		AddTime:         time.Now().Format(time.DateTime),
	}
	_, err = _mdb.Db.Collection("transfer_log").InsertOne(ctx, transferLog)
	if err != nil {
		logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:转赠记录添加失败,res=%v,dbErr:%v", user.ID, transferLog, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	transferLog = &entity.TransferLog{
		UID:             user.ID,
		Phone:           user.Username,
		InviteCode:      user.InviteCode,
		Other:           otherUser.ID,
		OtherPhone:      otherUser.Username,
		OtherInviteCode: otherUser.InviteCode,
		Type:            2,
		WID:             otherWid,
		TypeID:          types.ID,
		TypeName:        types.Name,
		TypeImg:         types.Img,
		TypeModule:      types.Module,
		TypeType:        types.Type,
		Num:             req.Num,
		Fee:             utils.DecimalIntByFloat(fee),
		Obtain:          otherUser.ID,
		OtherNum:        num,
		OtherObtainFee:  OtherObtainFee,
		AddTime:         time.Now().Format(time.DateTime),
	}
	_, err = _mdb.Db.Collection("transfer_log").InsertOne(ctx, transferLog)
	if err != nil {
		logs.Error("[warehouseHandler]用户%d WarehouseGoldTransfer err:转赠记录添加失败,res=%v,dbErr:%v", otherUser.ID, transferLog, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//商会间接收益
	if fee > 0 && (req.TypeID == 11 || req.TypeID == 12 || req.TypeID == 13) {
		for _, v := range *divideInto {
			if v.Role.ChamberMember.Conf.LowerRate == 0 {
				continue
			}
			var obtainFee int64
			otherTransferFee := utils.DecimalIntDiv(v.Role.ChamberMember.Conf.LowerRate, 100)
			obtainFee = utils.DecimalFloatByInt(utils.DecimalFloatMul(utils.DecimalIntByFloat(req.Num), otherTransferFee))
			material := new(db.WarehouseMaterial)
			_db.Model(material).Where("uid=? AND type_id=?", v.ID, req.TypeID).First(material)
			if material == nil || material.ID == 0 {
				err = fmt.Errorf("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料不存在,res=%v", v.ID, material)
				break
			}
			if err = tx.Model(material).Where("id=?", material.ID).Update("num", gorm.Expr("num+?", obtainFee)).Error; err != nil {
				err = fmt.Errorf("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料增加失败,res=%v,dbErr:%v", v.ID, material, err)
				break
			}
			materialLog := &entity.MaterialLog{
				UID:        v.ID,
				WID:        material.ID,
				TypeID:     material.TypeID,
				TypeName:   types.Name,
				TypeImg:    types.Img,
				TypeModule: types.Module,
				LinkID:     fmt.Sprintf("%d", wid),
				LinkTable:  "m_transfer_log",
				Ago:        material.Num,
				Num:        obtainFee,
				After:      material.Num + obtainFee,
				Remarks:    fmt.Sprintf("仓库-商会收益"),
				AddTime:    time.Now().Format(time.DateTime),
			}
			_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
			if err != nil {
				err = fmt.Errorf("[warehouseHandler]用户%d WarehouseGoldTransfer err:材料变更记录添加失败,res=%v,dbErr:%v", v.ID, materialLog, err)
				break
			}
			transferLog = &entity.TransferLog{
				UID:             user.ID,
				Phone:           user.Username,
				InviteCode:      user.InviteCode,
				Other:           otherUser.ID,
				OtherPhone:      otherUser.Username,
				OtherInviteCode: otherUser.InviteCode,
				Type:            3,
				WID:             material.ID,
				TypeID:          types.ID,
				TypeName:        types.Name,
				TypeImg:         types.Img,
				TypeModule:      types.Module,
				TypeType:        types.Type,
				Num:             req.Num,
				Fee:             utils.DecimalIntByFloat(fee),
				Obtain:          v.ID,
				OtherNum:        obtainFee,
				OtherObtainFee:  obtainFee,
				AddTime:         time.Now().Format(time.DateTime),
			}
			_, err = _mdb.Db.Collection("transfer_log").InsertOne(ctx, transferLog)
			if err != nil {
				err = fmt.Errorf("[warehouseHandler]用户%d WarehouseGoldTransfer err:转赠记录添加失败,res=%v,dbErr:%v", v.ID, transferLog, err)
				break
			}
		}
		if err != nil {
			logs.Error("%v", err)
			tx.Rollback()
			_ = mtx.AbortTransaction(ctx)
			return biz.SqlError
		}
	}
	tx.Commit()
	_ = mtx.CommitTransaction(ctx)
	return nil
}

func (d *WarehouseDao) GetInvestmentCore(ctx context.Context) *[]db.InvestmentCenterHasOneType {
	data := new([]db.InvestmentCenterHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(&db.InvestmentCenter{}).Preload("Types").Find(data)
	return data
}

func (d *WarehouseDao) InvExchange(ctx context.Context, exchange *entity.InvestmentExchangeLog) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	mtx, _ := _mdb.Client.StartSession()
	_ = mtx.StartTransaction()
	defer mtx.EndSession(ctx)
	var err error
	//1.扣除材料
	material := new(db.WarehouseMaterial)
	materialType := new(db.WarehouseMaterialHasOneType)
	_db.Model(material).Where("uid=? AND type_id=?", exchange.UID, exchange.ConsumeTypeID).Preload("Types").First(materialType)
	if materialType == nil || materialType.ID == 0 {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:材料不足,res=%v", exchange.UID, materialType)
		return biz.GoodsPayError
	}
	if exchange.ConsumeTypeID == 11 {
		exchange.ConsumeNum = utils.DecimalFloatMul(exchange.ConsumeNum, utils.DecimalIntByFloat(materialType.Types.Val))
		//exchange.ConsumeFee = utils.DecimalFloatMul(exchange.ConsumeFee, utils.DecimalIntByFloat(materialType.Types.Val))
		//exchange.ConsumeTotal = utils.DecimalFloatMul(exchange.ConsumeTotal, utils.DecimalIntByFloat(materialType.Types.Val))
	}
	num := utils.DecimalFloatByInt(exchange.ConsumeNum)
	//fee := utils.DecimalFloatByInt(exchange.ConsumeFee)
	//total := utils.DecimalFloatByInt(math.Floor(exchange.ConsumeTotal))
	if materialType.Num < num {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:材料不足,res=%v", exchange.UID, materialType)
		return biz.GoodsPayError
	}
	err = tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num-?", num)).Error
	if err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:修改材料失败,res=%v,dbErr:%v", exchange.UID, materialType, err)
		return biz.SqlError
	}
	//2.添加材料变动日志
	collection := d.repo.Mongo.Db.Collection("material_log")
	materialLog := &entity.MaterialLog{
		UID:        exchange.UID,
		WID:        materialType.ID,
		TypeID:     materialType.TypeID,
		TypeName:   materialType.Types.Name,
		TypeImg:    materialType.Types.Img,
		TypeModule: materialType.Types.Module,
		LinkID:     "",
		LinkTable:  "m_investment_exchange_log",
		Ago:        materialType.Num,
		Num:        -num,
		After:      materialType.Num - num,
		Remarks:    "投资中心-兑换",
		AddTime:    exchange.AddTime,
	}
	_, err = collection.InsertOne(ctx, materialLog)
	if err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:添加材料变动日志失败,res=%v,dbErr:%v", exchange.UID, materialLog, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//3.添加材料
	materialType = new(db.WarehouseMaterialHasOneType)
	_db.Model(material).Where("uid=? AND type_id=?", exchange.UID, exchange.TypeID).Preload("Types").First(materialType)
	if exchange.TypeID == 11 {
		exchange.Num = utils.DecimalFloatByInt(utils.DecimalFloatMul(utils.DecimalIntByFloat(exchange.Num), utils.DecimalIntByFloat(materialType.Types.Val)))
		exchange.Fee = utils.DecimalFloatMul(exchange.Fee, utils.DecimalIntByFloat(materialType.Types.Val))
		exchange.Total = utils.DecimalFloatMul(exchange.Total, utils.DecimalIntByFloat(materialType.Types.Val))
	} else {
		exchange.Total = math.Round(exchange.Total)
	}
	err = tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num+?", exchange.Total)).Error
	if err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:修改材料失败,res=%v,dbErr:%v", exchange.UID, materialType, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//4.添加材料变动日志
	materialLog = &entity.MaterialLog{
		UID:        exchange.UID,
		WID:        materialType.ID,
		TypeID:     materialType.TypeID,
		TypeName:   materialType.Types.Name,
		TypeImg:    materialType.Types.Img,
		TypeModule: materialType.Types.Module,
		LinkID:     "",
		LinkTable:  "m_investment_exchange_log",
		Ago:        materialType.Num,
		Num:        utils.DecimalFloatByInt(exchange.Total),
		After:      materialType.Num + utils.DecimalFloatByInt(exchange.Total),
		Remarks:    "投资中心-兑换",
		AddTime:    exchange.AddTime,
	}
	_, err = collection.InsertOne(ctx, materialLog)
	if err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:添加材料变动日志失败,res=%v,dbErr:%v", exchange.UID, materialLog, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//5.添加兑换记录
	collection = d.repo.Mongo.Db.Collection("investment_exchange_log")
	_, err = collection.InsertOne(ctx, exchange)
	if err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:添加兑换记录失败,res=%v,dbErr:%v", exchange.UID, exchange, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//6.修改投资中心数据
	center := new(db.InvestmentCenter)
	if err = tx.Model(center).Where("type_id=?", exchange.TypeID).Update("num", gorm.Expr("num-?", exchange.Num)).Error; err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:修改投资中心数据失败,res=%v,dbErr:%v", exchange.UID, exchange, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	if err = tx.Model(center).Where("type_id=?", exchange.ConsumeTypeID).Update("num", gorm.Expr("num+?", num)).Error; err != nil {
		logs.Error("[investmentHandler]用户%d InvestmentExchange err:修改投资中心数据失败,res=%v,dbErr:%v", exchange.UID, exchange, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	tx.Commit()
	_ = mtx.CommitTransaction(ctx)
	return nil
}

func (d *WarehouseDao) GetInvestmentLog(ctx context.Context, pageSize int64) *[]entity.InvestmentExchangeLog {
	collection := d.repo.Mongo.Db.Collection("investment_exchange_log")
	findOptions := options.Find().SetSort(bson.M{"addTime": -1}).SetLimit(pageSize)
	cur, err := collection.Find(ctx, bson.D{}, findOptions)
	var res []entity.InvestmentExchangeLog
	for cur.Next(ctx) {
		var result entity.InvestmentExchangeLog
		err = cur.Decode(&result)
		if err == mongo.ErrNoDocuments {
			return nil
		}
		res = append(res, result)
	}
	return &res
}

func (d *WarehouseDao) WarehouseExtract(ctx context.Context, materialType *db.WarehouseMaterialHasOneType, extract *entity.WarehouseMoneyExtract) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	//1.扣除材料数量
	material := new(db.WarehouseMaterial)
	if err := tx.Model(material).Where("id=?", materialType.ID).Update("num", gorm.Expr("num-?", extract.Money)).Error; err != nil {
		logs.Error("[warehouseExtract]用户%d WarehouseExtract err:修改材料失败,res=%v,dbErr:%v", extract.UID, materialType, err)
		return biz.SqlError
	}
	//2.添加材料变动日志
	collection := _mdb.Db.Collection("material_log")
	materialLog := &entity.MaterialLog{
		UID:        extract.UID,
		WID:        materialType.ID,
		TypeID:     extract.TypeID,
		TypeName:   extract.TypeName,
		TypeImg:    extract.TypeImg,
		TypeModule: extract.TypeModule,
		LinkID:     "",
		LinkTable:  "m_warehouse_money_extract_log",
		Ago:        materialType.Num,
		Num:        -extract.Money,
		After:      materialType.Num - extract.Money,
		Remarks:    "提现",
		AddTime:    extract.AddTime,
	}
	_, err := collection.InsertOne(ctx, materialLog)
	if err != nil {
		logs.Error("[warehouseExtract]用户%d WarehouseExtract err:添加材料变动日志失败,res=%v,dbErr:%v", extract.UID, materialLog, err)
		tx.Rollback()
		return biz.SqlError
	}
	//3.添加提现记录
	collection = _mdb.Db.Collection("warehouse_money_extract_log")
	_, err = collection.InsertOne(ctx, extract)
	if err != nil {
		logs.Error("[warehouseExtract]用户%d WarehouseExtract err:添加提现记录失败,res=%v,dbErr:%v", extract.UID, extract, err)
		tx.Rollback()
		return biz.SqlError
	}
	tx.Commit()
	return nil
}

func (d *WarehouseDao) CardBuyCount(ctx context.Context, uid uint) int64 {
	count, _ := d.repo.Mongo.Db.Collection("goods_order").
		CountDocuments(ctx, bson.M{
			"uid":       uid,
			"goodsType": 1,
			"payStatus": 1,
		})
	return count
}

func NewWarehouseDao(m *repo.Manager) *WarehouseDao {
	return &WarehouseDao{
		repo: m,
		base: NewBaseDao(m),
	}
}
